//    Copyright (C) Kherty.  All rights reserved.
using System;
using System.Diagnostics;
using System.Diagnostics.Contracts;
using OpenLS.Core.Serialization;

namespace OpenLS.Spreadsheet
{
    public partial class Borders : IOfficeXmlSerializable
    {
        public Borders()
        {
            Outline = true;
        }

        public Borders(BorderStyle left, BorderStyle top, BorderStyle right, BorderStyle bottom)
        {
            Left = Border.Create(left);
            Top = Border.Create(top);
            Right = Border.Create(right);
            Bottom = Border.Create(bottom);
            Outline = true;
        }
        public Borders(Border left, Border top, Border right, Border bottom)
        {
            Left = left;
            Top = top;
            Right = right;
            Bottom = bottom;
            Outline = true;
        }
        public Borders(Border border)
            : this(border, border, border, border)
        {
        }

        public Borders(BorderStyle s) : this(s, s, s, s) { }
#if DEBUG
        public override string ToString()
        {
            return base.ToString() + FormattingRecord.StringOf(Bottom, Diagonal, DiagonalDown, DiagonalUp, Horizontal, Left, Outline, Right, Top, Vertical);
        }
#endif
        const string xmlName = "border";

        ///<summary>
        /// Get the left border
        ///</summary>
        public Border Left { get; internal set; }

        private Border _right;
        public Border Right
        {
            get { return _right; }
            internal set { _right = value; }
        }

        ///<summary>
        /// Get the top border
        ///</summary>
        public Border Top { get; internal set; }

        ///<summary>
        /// Get the bottom border
        ///</summary>
        public Border Bottom { get; internal set; }

        private Border _diagonal;

        ///<summary>
        /// get the diagonal border
        ///</summary>
        public Border Diagonal
        {
            get { return _diagonal; }
            internal set {
                _diagonal = value;
            }
        }

        ///<summary>
        /// Get the vertical border 
        ///</summary>
        public Border Vertical { get; internal set; }

        ///<summary>
        /// Get the horizontal border
        ///</summary>
        public Border Horizontal { get; internal set; }

        ///<summary>
        /// Get the diagonal up border
        ///</summary>
        public Border DiagonalUp { get; internal set; }

        ///<summary>
        /// Get the diagonal down border
        ///</summary>
        public Border DiagonalDown { get; internal set; }

        ///<summary>
        /// Is it on outline border?
        ///</summary>
        public bool Outline { get; internal set; }


        internal Borders Clone()
        {
            var result = new Borders
                             {
                                 Bottom = Bottom,
                                 Left = Left,
                                 Top = Top,
                                 Right = Right,
                                 Diagonal = Diagonal,
                                 Vertical = Vertical,
                                 Horizontal = Horizontal,
                                 DiagonalUp = DiagonalUp,
                                 DiagonalDown = DiagonalDown,
                                 Outline = Outline
                             };
            return result;
        }
        public override int GetHashCode()
        {
            unchecked
            {
                int result = (_right != null ? _right.GetHashCode() : 0);
                result = (result*397) ^ (Left != null ? Left.GetHashCode() : 0);
                result = (result*397) ^ (Top != null ? Top.GetHashCode() : 0);
                result = (result*397) ^ (Bottom != null ? Bottom.GetHashCode() : 0);
                result = (result*397) ^ (Diagonal != null ? Diagonal.GetHashCode() : 0);
                result = (result*397) ^ (Vertical != null ? Vertical.GetHashCode() : 0);
                result = (result*397) ^ (Horizontal != null ? Horizontal.GetHashCode() : 0);
                result = (result*397) ^ (DiagonalUp != null ? DiagonalUp.GetHashCode() : 0);
                result = (result*397) ^ (DiagonalDown != null ? DiagonalDown.GetHashCode() : 0);
                result = (result*397) ^ Outline.GetHashCode();
                return result;
            }
        }
        public override bool Equals(object obj)
        {
            if (ReferenceEquals(null, obj)) return false;
            if (ReferenceEquals(this, obj)) return true;
            if (obj.GetType() != typeof (Borders)) return false;
            return Equals((Borders) obj);
        }
        bool Equals(Borders b)
        {
            Contract.Ensures(!Contract.Result<bool>() || GetHashCode() == b.GetHashCode());
            if (ReferenceEquals(null, b)) return false;
            if (ReferenceEquals(this, b)) return true;
            return Equals(b._right, _right) && Equals(b.Left, Left) && Equals(b.Top, Top) && Equals(b.Bottom, Bottom) && Equals(b.Diagonal, Diagonal) && Equals(b.Vertical, Vertical) && Equals(b.Horizontal, Horizontal) && Equals(b.DiagonalUp, DiagonalUp) && Equals(b.DiagonalDown, DiagonalDown) && b.Outline.Equals(Outline);
        }

        #region IOfficeXmlSerializable Members

        void IOfficeXmlSerializable.ReadXml(ReadContext context)
        {
            using (ReadContext c = context.Read(xmlName))
            {
                Outline = c.GetOptionalBoolean("outline", true);
                while (c.ReaderLocalName != null)
                {
                    switch (c.ReaderLocalName)
                    {
                        case "left":
                            Left = c.ReadElementAs<Border>("left");
                            break;
                        case "right":
                            Right = c.ReadElementAs<Border>("right");
                            break;
                        case "top":
                            Top = c.ReadElementAs<Border>("top");
                            break;
                        case "bottom":
                            Bottom = c.ReadElementAs<Border>("bottom");
                            break;
                        case "diagonal":
                            Diagonal = c.ReadElementAs<Border>("diagonal");
                            break;
                        case "vertical":
                            Vertical = c.ReadOptionalElementAs<Border>("vertical");
                            break;
                        case "horizontal":
                            Horizontal = c.ReadOptionalElementAs<Border>("horizontal");
                            break;
                        case "diagonalUp":
                            Vertical = c.ReadOptionalElementAs<Border>("diagonalUp");
                            break;
                        case "diagonalDown":
                            Vertical = c.ReadOptionalElementAs<Border>("diagonalDown");
                            break;
                        default: throw new NotSupportedException();
                    }
                }
            }
        }

        void IOfficeXmlSerializable.WriteXml(WriteContext context)
        {
            using (WriteContext c = context.Write(xmlName))
            {
                c.SetOptionalBoolean("outline", Outline, true);
                c.WriteOptionalElementAs(Left, "left");
                c.WriteOptionalElementAs(Right, "right");
                c.WriteOptionalElementAs(Top, "top");
                c.WriteOptionalElementAs(Bottom, "bottom");
                c.WriteOptionalElementAs(Diagonal, "diagonal");
                c.WriteOptionalElementAs(Vertical, "vertical");
                c.WriteOptionalElementAs(Horizontal, "horizontal");
                c.WriteOptionalElementAs(DiagonalUp, "diagonalUp");
                c.WriteOptionalElementAs(DiagonalDown, "diagonalDown");
            }
        }

        #endregion

        internal Border GetBorder(BorderType borderType)
        {
            switch (borderType)
            {
                case BorderType.BottomEdge:
                    return Bottom;
                case BorderType.DiagonalDown:
                    return DiagonalDown;
                case BorderType.DiagonalUp:
                    return DiagonalUp;
                case BorderType.RightEdge:
                    return Right;
                case BorderType.TopEdge:
                    return Top;
                case BorderType.LeftEdge:
                    return Left;
                case BorderType.All:
                case BorderType.InsideHorizontal:
                case BorderType.InsideVertical:
                case BorderType.OutsideEdge:
                    throw new NotSupportedException();
                default:
                    throw new NotSupportedException();
            }
        }

        internal double GetBorderThickness(BorderType leftEdge)
        {
            var item = GetBorder(leftEdge);
            if (item != null)
                return 1;
            return 0;
        }
    }
}
